<?php
namespace App\Services\Promotion;
use App\Common\BnFormatConfig;
use App\Common\ResponseCode;
use App\Common\Tools;
use App\Exceptions\BusinessException;
use App\Params\Backend\CouponAssignParams;
use App\Params\Backend\CouponListParams;
use App\Params\Backend\CouponUpdateParam;
use App\Params\H5\MyCouponListParams;
use App\Repository\CouponAssignLogRepository;
use App\Repository\CouponRepository;
use App\Repository\CustomerCouponRepository;
use App\Repository\CustomerRepository;
use App\Services\BaseService;
use App\Traits\Calculator;
use App\Traits\DateTimeTrait;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use function Sodium\compare;

/**
 * 优惠券相关业务类
 *
 * @author WangBin
 * @date 2021-09-24
 * @package App\Http\Services\Promotion
 */
class CouponService extends BaseService
{
    use DateTimeTrait, Calculator;

    /**
     * 保存优惠券信息
     *
     * @param CouponUpdateParam $param
     * @return mixed
     * @throws BusinessException
     */
    public function update(CouponUpdateParam $params)
    {
        $data = $params->toArray();
        // 开始时间 - 结束时间 校验
        if(strtotime($data['time_range'][0]) >= strtotime($data['time_range'][1])) {
            throw new BusinessException(ResponseCode::TIME_RANGE_ERROR);
        }
        $data['start_at'] = $data['time_range'][0];
        $data['end_at'] = $data['time_range'][1];
        $data['coupon_bn'] = Tools::buildBn(BnFormatConfig::COUPON_BN_KEY);
        $data['goods_bind'] = [];
        $data['customer_bind'] = [];
        unset($data['time_range']);
        return CouponRepository::getInstance()->save($data, $params->getCouponId());
    }

    /**
     * 优惠券列表
     *
     * @param CouponListParams $params
     * @return array
     */
    public function getList(CouponListParams $params)
    {
        $data = $params->toArray();
        $coupons = CouponRepository::getInstance()->getList($data);
        $result = $this->toList($coupons, $params->getPage(), $params->getPageSize());
        $result['list']->each(function ($item) {
            $item->status_name = $this->getTimeRangeStatus($item->start_at, $item->end_at)['name'];
        });
        return $result;
    }

    /**
     * 停启用优惠券
     *
     * @param int $couponId
     * @return int|mixed
     * @throws BusinessException
     */
    public function enable(int $couponId)
    {
        $coupon = CouponRepository::getInstance()->getById($couponId);
        if(is_null($coupon)) {
            throw new BusinessException(ResponseCode::COUPON_NOT_FOUND);
        }
        $isActive = $coupon->is_active ? 0 : 1;
        $data = ['is_active' => $isActive];
        return CouponRepository::getInstance()->save($data, $couponId);
    }

    /**
     * 查看优惠券
     *
     * @param int $couponId
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function get(int $couponId)
    {
        return CouponRepository::getInstance()->getById($couponId);
    }

    /**
     * 保存发放优惠券任务
     *
     * @param CouponAssignParams $params
     * @return mixed
     */
    public function saveAssignLog(CouponAssignParams $params)
    {
        $logId = CouponAssignLogRepository::getInstance()->save($params->toArray());
        if($logId) {
            // 使用队列 todo
            return $this->assign($logId);
        }
        return false;
    }

    /**
     * 执行发放优惠券任务
     *
     * @param int $logId
     * @return false|void
     * @throws BusinessException
     */
    public function assign(int $logId)
    {
        // 获取发放任务
        $assignLog = CouponAssignLogRepository::getInstance()->getById($logId);
        // 获取优惠券
        $coupon = CouponRepository::getInstance()->getById($assignLog->coupon_id);
        if(is_null($coupon)) {
            Log::debug("[发放优惠券] 优惠券({$assignLog->coupon_id})不存在");
            return false;
        }
        if(!empty($assignLog->status)) {
            Log::debug("[发放优惠券] 优惠券({$coupon->coupon_bn})已被处理，状态为{$assignLog->status}");
            return false;
        }
        if($coupon->is_active == 0 || !$this->check($coupon->start_at, $coupon->end_at)) {
            Log::debug("[发放优惠券] 优惠券({$coupon->coupon_bn})活动时间已结束");
            return false;
        }
        $totalHave = 0; // 总发放数量
        try {
            DB::beginTransaction();
            // 修改发放任务为 进行中
            CouponAssignLogRepository::getInstance()->save(['status' => 1], $logId);
            $customer = null;
            switch ($assignLog->type) {
                case 'GROUP':
                    $customer = CustomerRepository::getInstance()->getByGroupId($assignLog->entity_id);
                    break;
            }
            // 开始发放
            $customer->each(function ($item) use ($assignLog, $coupon, $totalHave) {
                // 客户 + 优惠券是否存在
                if(CustomerCouponRepository::getInstance()->checkExist($item->customer_id, $assignLog->coupon_id)) {
                    Log::debug("[发放优惠券] 优惠券({$coupon->coupon_bn})已存在客户({$item->nickname})中");
                    return true;
                }
                $data = [
                    'customer_id' => $item->customer_id,
                    'coupon_id' => $assignLog->coupon_id,
                    'nickname' => $item->nickname,
                    'num' => $assignLog->num,
                    'name' => $coupon->name,
                    'amount' => $coupon->amount,
                    'discount' => $coupon->discount,
                    'start_at' => $coupon->start_at,
                    'end_at' => $coupon->end_at
                ];
                $ret = CustomerCouponRepository::getInstance()->save($data);
                if(!$ret) {
                    throw new \Exception('发放失败');
                }

                $totalHave += $assignLog->num;
            });
            DB::commit();
            $data = ['status' => 2, 'finished_at' => $this->getCurrDateTime()];
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error("[发放优惠券] 优惠券({$coupon->coupon_bn})发放出错：{$exception->getMessage()}");
            $data = ['status' => 3, 'finished_at' => $this->getCurrDateTime()];
        }
        // 更新优惠券发放数量
        CouponRepository::getInstance()->save(['total_have' => $coupon->total_have + $totalHave], $coupon->coupon_id);
        // 更新优惠券发放数量
        CouponAssignLogRepository::getInstance()->save($data, $assignLog->log_id);
        return true;
    }

    /**
     *
     * 获取客户优惠券列表
     *
     * @param MyCouponListParams $params
     * @return array
     */
    public function getMyList(MyCouponListParams $params)
    {
        $list = CouponRepository::getInstance()->getMyList($params->toArray());
        $result = $this->toList($list, $params->getPage(), $params->getPageSize());
        $result['list']->each(function ($item) {
            $item->status = $this->getTimeRangeStatus($item->start_at, $item->end_at);
            // 格式化优惠券有效期时间
            $item->start_at = $this->formatDateTime($item->start_at, 'Y-m-d');
            $item->end_at = $this->formatDateTime($item->end_at, 'Y-m-d');
        });
        return $result;
    }

    /**
     * 获取客户可用优惠券的总数
     *
     * @param int $customerId
     * @return int
     */
    public function getCustomerCouponNum(int $customerId)
    {
        return CouponRepository::getInstance()->getMyList(['customer_id' => $customerId, 'type' => 'unused'])->count();
    }

    /**
     * 获取结算商品的优惠券优惠信息
     *
     * @param int $customerId
     * @param float $orderAmount
     * @return int[]
     */
    public function getCouponDiscount(int $customerId, float $orderAmount)
    {
        // 计算最优优惠
        $result = ['coupon_id' => 0, 'coupon_discount' => 0];
        // 可用优惠券
        $filter = ['customer_id' => $customerId, 'type' => 'unused', 'status' => 1];
        $couponList = CouponRepository::getInstance()->getMyList($filter)->get();
        $couponList->each(function ($item) use (&$result, $orderAmount) {
            if($this->compare($orderAmount, $item->amount) >= 0) {
                if($this->compare($item->discount, $result['coupon_discount']) == 1) {
                    $result['coupon_id'] = $item->coupon_id;
                    $result['coupon_discount'] = $item->discount;
                }
            }
        });
        return $result;
    }
}
